/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2004
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
*
* Author's email : insane@dees.ufmg.br
* Author's Website : http://www.dees.ufmg.br/insane
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package br.ufmg.dees.insane.model.xfemModel.xfemElement;

import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.femModel.elementNode.ElementNode;
import br.ufmg.dees.insane.model.xfemModel.xfemelementNode.XFEMElementNode;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IPoint3d;
import br.ufmg.dees.insane.util.IVector;

/**
 * @author Kelson Wolff
 *
 */
public class XFEMElementT6 extends XFEMTriangular {
	
	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 
	 */
	public XFEMElementT6() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	public int getNbFaces(){
		return 3;
	}
	
	public int getNbNodesFace(){
		return 3;
	}
		
	public ArrayList<ElementNode> getCCWIncidence(){
//		setting aside initial node from XFEMElement incidence. Initial node is picked up
//		like follows: the initial node is sorted if it has minor "x" coordinate between
//		all nodes from incidence. If more than one node has equal minor "x" coordinate
//		the selected initial node with minor "y" coordinate is taken.
		
		int nbNodes = this.getNbNodes();
		ArrayList<ElementNode> ccwIncidence = new ArrayList<ElementNode>();
		ArrayList<ElementNode> auxIncidence = new ArrayList<ElementNode>();
		for(int i=0; i<nbNodes; i++){
			auxIncidence.add((this.getIncidence()).get(i));
		}
		ListIterator auxNodes = auxIncidence.listIterator();
		double xMinor = 1.0e15;
		double yMinor = 1.0e15;
		double lastXMinor = 0.0;
		double lastYMinor = 0.0;
		XFEMElementNode initialNode = new XFEMElementNode();
		XFEMElementNode minorInitialNode = new XFEMElementNode();
	
		while(auxNodes.hasNext()){
			XFEMElementNode auxNo = (XFEMElementNode) auxNodes.next();
			if(auxNo.getX() <= xMinor) {
				lastXMinor = xMinor;
				lastYMinor = yMinor;
				xMinor = auxNo.getX();
				yMinor = auxNo.getY();
				initialNode.setNode(auxNo.getNode()); //= auxNo;
				if(xMinor == lastXMinor) {
					if(yMinor < lastYMinor){
						initialNode.setNode(auxNo.getNode()); // = auxNo;
						minorInitialNode.setNode(initialNode.getNode()); // = initialNode;
						yMinor = initialNode.getY();
					}
					else{
						initialNode.setNode(minorInitialNode.getNode()); // = minorInitialNode;
						yMinor = initialNode.getY();
					}
				}
			}
			minorInitialNode.setNode(initialNode.getNode()); // = initialNode;
		}
		
		ccwIncidence.add(initialNode);
		IVector iNodeVector = new IVector(initialNode.getCoords());
		
		double xCentroid = 0.0;
		double yCentroid = 0.0;
		double zCentroid = 0.0;

//		create the centroid (elementCentroid) of the points/nodes of the element
		
		auxNodes = auxIncidence.listIterator();
		while(auxNodes.hasNext()){
			XFEMElementNode auxNo = (XFEMElementNode) auxNodes.next();
			xCentroid += auxNo.getX();
			yCentroid += auxNo.getY();
			zCentroid += auxNo.getZ();
		}
		IPoint3d elementCentroid = new IPoint3d(xCentroid/(double)nbNodes,
					 yCentroid/(double)nbNodes,zCentroid/(double)nbNodes);
		IVector centroidVector = new IVector(elementCentroid.getCoords());
		IVector auxCentroidVector = new IVector(3);
		auxCentroidVector.zero();
		auxCentroidVector.sub(iNodeVector,centroidVector);
		IVector refVector = new IVector(auxCentroidVector);
		
//		create the ccw (counter-clock-wise) order of the nodes of the element
		
		IVector nodeVector = new IVector(3);
		nodeVector.zero();
		IVector dotVector = new IVector(3);
		dotVector.zero();
		IVector crossVector = new IVector(3);
		crossVector.zero();
		int count = 1;
		
		for(int i=0; i<nbNodes; i++){
			auxNodes = auxIncidence.listIterator();
			while(auxNodes.hasNext()){
				XFEMElementNode actualNode = (XFEMElementNode) auxNodes.next();
				nodeVector.set(actualNode.getPoint().getCoords());
				dotVector.sub(nodeVector,centroidVector);
				crossVector.setElement(0,-(dotVector.getElement(1)));
				crossVector.setElement(1,+(dotVector.getElement(0)));
				crossVector.setElement(2,(dotVector.getElement(2)));
				if((refVector.dot(dotVector) > 0) && (refVector.dot(crossVector) < 0)){
					ccwIncidence.add(actualNode);
					refVector.set(dotVector);
					count++;
					auxNodes.remove();
				}
				nodeVector.zero();
				dotVector.zero();
				crossVector.zero();
			}
		}
		ccwIncidence.remove(this.getNbNodes());
		return ccwIncidence;
	}
	
	public String[] getCCWIncidenceString(){
		
		int i=0;
		String[] ccwIncid = new String[this.getNbNodes()];
		ArrayList<ElementNode> inciden = this.getCCWIncidence();
		ArrayList<ElementNode> incid = new ArrayList<ElementNode>();
		incid.addAll(inciden);
		ListIterator nodes = incid.listIterator();
		while(nodes.hasNext()){
			XFEMElementNode node = (XFEMElementNode) nodes.next();
			ccwIncid[i] = node.getLabel();
			i++;
		}
		return ccwIncid;
	}
	
	public void setCCWIncidence(){
		
		ArrayList<ElementNode> inciden = this.getCCWIncidence();
		ArrayList<ElementNode> incid = new ArrayList<ElementNode>();
		incid.addAll(inciden);
		this.setIncidence(incid);
	}

	/**
	 * Gets the area of this Element.
	 * @return Returns the area of this Element.
	 */
	public double getMyArea() {
		// TODO Auto-generated method stub
		this.setCCWIncidence();
		IMatrix area = new IMatrix(3,3);
		ListIterator coordsList = this.getNodalCoords().listIterator();
		int counter1 = 0;
		int counter2 = 0;
		int index = 0;
		while(coordsList.hasNext()){
			double[] coords = new double[3];
			coords = (double[]) coordsList.next();
			if(counter1 == counter2){
				area.setRow(index,coords);
				index++;
				counter2 = counter2 + 2;
			}
			counter1 = counter1 + 1;
		}
		area.setElement(0,2,1.0);
		area.setElement(1,2,1.0);
		area.setElement(2,2,1.0);
		return (0.5 * area.determinantLU());
	}

	@Override
	public XFEMElement cloneMyself() {
		// TODO Auto-generated method stub
		XFEMElement clone = new XFEMElementT6();
		
		clone.setUpdated(this.isUpdated);
		clone.setEnrichmentItemList(this.getEnrichmentItemList());
		clone.setIntegrationOrder(this.getIntegrationOrder());
		clone.setLabel(this.getLabel());
		clone.setIncidence(this.getIncidence());
		clone.setAnalysisModel(this.getAnalysisModel());
		clone.setConstitutiveModel(this.getConstitutiveModel());
		clone.setShape(this.getShape());
		clone.setMyProblemDriver(this.getMyProblemDriver());
		clone.addDegenerations(this.getDegenerations());
		clone.setElementValues(this.getElementValues());
		
		return clone;
	}

}
